/*:
* @plugindesc (v1.04)簡單雙物品合成
* @author 小c
* @version 1.0.4
* @date 1/12/2021
*
* @param Datas
* @text -----數據-----
*
* @param Recipe List
* @parent Datas
* @text 配方列表
* @type struct<recipe>[]
* @desc 配方列表，每個項目中物品/武器/護甲指定其一即可
* @default []
*
* @param Default Produce
* @parent Datas
* @text 默認產出
* @type struct<synthesisItem>
* @desc 沒有找到配方時的產出物
* @default {"item":"0","weapon":"0","armor":"0"}
*
* @param Failure Produce
* @parent Datas
* @text 失敗產出
* @type struct<synthesisItem>
* @desc 合成失敗時的產出物
* @default {"item":"0","weapon":"0","armor":"0"}
*
* @param Synthesis Condition
* @parent Datas
* @text 合成的條件
* @type note
* @default "//recipe1 和 recipe2 表示兩個合成原料的data對象\n//produce 表示合成產物的data對象\n//布爾變量condition表示是否滿足條件\ncondition = true;"
* @desc 布爾變量condition為true時滿足條件，允許合成該項
*
* @param Synthesis Success Rate
* @parent Datas
* @text 合成成功率公式
* @type note
* @desc 其中produce表示成功產物
* @default "//recipe1 和 recipe2 表示兩個合成原料的data對象\n//produce 表示合成產物的data對象\n//浮點變量rate表示成功率\nrate = 1;"
*
* @param UIs
* @text -----界面-----
*
* @param Show In Main Menu
* @parent UIs
* @text 主選單顯示合成指令
* @type boolean
* @on 顯示
* @off 不顯示
* @default true
* @desc 使用YEP主選單管理時可設定為false，在那邊配置
*
* @param Main Menu Commamd
* @parent UIs
* @text 主選單命令名稱
* @default 合成
*
* @param Left Width
* @parent UIs
* @text 界面左側寬度
* @default Graphics.boxWidth / 3
*
* @param Type Commands
* @parent UIs
* @type struct<synthesisType>[]
* @text 類型视窗命令列表
* @desc 物品類型视窗指令文字與效果
* @default ["{\"name\":\"物品\",\"condition\":\"\\\"condition = DataManager.isItem(item);\\\"\"}","{\"name\":\"武器\",\"condition\":\"\\\"condition = DataManager.isWeapon(item);\\\"\"}","{\"name\":\"防具\",\"condition\":\"\\\"condition = DataManager.isArmor(item);\\\"\"}"]
*
* @param Recipe Window Title
* @parent UIs
* @text 合成视窗標題
* @default 合成材料選擇
*
* @param Result Command Name
* @parent UIs
* @text 預覽指令名稱
* @desc 隸屬於命令選單
* @default 預覽
*
* @param Select Command Name
* @parent UIs
* @text 選擇材料指令名稱
* @desc 隸屬於命令選單
* @default 選擇
*
* @param Synthesis Command Name
* @parent UIs
* @text 合成指令名稱
* @desc 隸屬於結果預覽選單
* @default 合成
*
* @param Cancel Command Name
* @parent UIs
* @text 取消指令名稱
* @desc 隸屬於結果預覽選單
* @default 取消
*
* @param Result Window Title
* @parent UIs
* @text 預覽界面標題
* @default 合成結果
*
* @param No Recipe Text
* @parent UIs
* @text 沒有物品的提示文字
* @default 無
*
* @param Synthesis Result Text
* @parent UIs
* @text 結果提升文字
* @desc 文字支持各種文本代碼，%1為合成產物名稱。
* @default 成功合成 \c[6]%1\c[0]！
*
* @param Synthesis Failure Text
* @parent UIs
* @text 不能合成文字
* @default %3<br>目前不可合成！
* @desc %1-原料1名稱 %2-原料2名稱 %3-產物名稱 br-換行符
* 換行符符號實際以默認參數為準
*
* @param Synthesis Not Success Text
* @parent UIs
* @text 合成失敗文字
* @desc %1-成功產物名稱 %2-失敗產物名稱
* @default \c[6]%1\c[0]合成失敗，得到\c[6]%2\c[0]！
* 
* @help
* 簡單的雙物品合成系統
* 此合成系統的原料是無序的，即A+B與B+A為同一個配方
*
* 基本合成配方請配置插件參數及默認產物，默認產物非必需。
* 玩家所選材料找不到配方時將得到默認產物。
* 合成成功率可自行指定，修改插件參數的代碼即可
* 合成失敗時，失敗產物請配置插件參數，必需
* 如果你的失敗產物是動態的，請複寫以下函數
* Scene_Synthesis.prototype.failureResult
* 參數recipe1，recipe2，produce分別表示原料和成功產物的data對象
* 該函數返回失敗產物的data對象
*
* 此插件的合成配方以及界面都有其擴展性，詳述如下：
*
* 1. 配方擴展
* 外部配方導入接口是函數CP.SynthesisManager.loadExtRecipes()
* 
* 此函數允許拋出一個LoadRecipeError異常
* 這個異常通過CP.Synthesis.throwLoadRecipeError(message)進行拋出
* 此異常可用於異步讀取文件時的等待或其他用處
* 比如：用XMLHttpRequest讀取文件在沒有得到返回數據時拋出異常阻塞執行，
* 直到結果返回再進行下一步操作。
* 拋出異常後DataManager.isDatabaseLoaded函數會返回false後再執行一次。
* 
* 此函數返回一個對象數組，數組中的每個元素為一個配方data對象。
* 配方data對象的格式為（舉例）
* recipe = {recipe1: ["item", 1], recipe2:["weapon", 2], produce: ["armor", 3]};
* 即用一個數組[物品類型, 物品id]來表示一個原料或者產物。
*
* 此格式的配方會被轉換成內部配方對象（Game_Recipe類）
* Game_Recipe構造方法接受3個參數【原料1，原料2，產物】，都為數據庫data
* 對象（$dataXXXs成員）
* Game_Recipe類有3個私有屬性【原料1，原料2，產物】，這3個屬性都是
* Game_SynthesisItem類（Game_Item子類）對象。
* 可以通過recipe.recipeObject()來得到配方data對象。
* Game_SynthesisItem類會自動將獨立物品轉換為數據庫物品。
*
* 遊戲中的所有配方數據將被儲存在一個Game_RecipeList類對象中
* 可以通過recipeList.simpleData()得到他們對應的配方data對象數組。
* 因此可以構造新的Game_RecipeList對象再轉換成配方data數組的方法寫入外部
* 配方。
* Game_RecipeList類有以下方法
* recipeList.push(recipe)  添加一個Game_Recipe配方，此方法會篩選掉重複的部
* 分，成功添加返回true，若失敗【重複或者參數錯誤】，返回false
* recipeList.appendRecipes(recipes) 添加一個Game_Recipe數組到配方中並剔除重
* 復，返回成功添加的數量
* Game_RecipeList有一個迭代器來進行遍歷元素
* recipeList.startIterate() 開始遍歷，迭代器指針初始化
* recipeList.hasNext() 是否有下一個對象
* recipeList.next() 得到下一個對象，迭代器指針後移一位
*
* push和appendRecipes方法會重置迭代器狀態。
*
* 2. 界面（Scene_Synthesis）擴展
* 视窗有6個部分
* 幫助视窗this._helpWindow，Window_Help對象（最上）
* 
* 物品類型视窗this._typeWindow，Window_TypeSelect對象（左上）
* 類型视窗有個游標移動時的回調函數Scene_Synthesis.prototype.onTypeSelect，
* 此函數的作用在於實時刷新物品列表视窗的內容，刷新規則由插件參數決定
* 此视窗執行確認將會激活物品列表视窗。
*
* 物品列表视窗this._listWindow，Window_SynthesisItemList對象（左）
* 此為Window_ItemList的子類
* 物品列表內容由物品類型视窗確定
* 此视窗為原料视窗選擇原料
*
* 原料视窗this._recipeWindow，Window_RecipeItem對象（右下）
* 此视窗顯示兩個原料位，提供玩家放置原料
* 執行確認，當選中的原料位沒有原料時，激活物品類型视窗，否則激活預覽命
* 令视窗
*
* 預覽命令视窗this._commandWindow，Window_SynthesisCommand對象（下）
* 此视窗提供【選擇材料】和【預覽】兩個命令
* 【選擇材料】（symbol: select）將激活物品類型视窗來選擇新材料
* 【預覽】（symbol: result）將激活結果預覽视窗
*
* 結果預覽视窗this._resultWindow，Window_SynthesisResult對象
* 預覽命令视窗執行預覽命令後，將在此视窗執行結果顯示
* 如果有合成結果，將有兩個選項可選
* 【合成】（symbol: synthesis），執行合成結果，得到合成產物
* 【取消】（symbol：cancel），返回預覽命令视窗
* 如果不滿足【合成條件】插件參數，則會額外顯示【不能合成文字】的內容
* 【不能合成文字】的換行轉義符為<br>，請留意
* 【不能合成文字】支持各種轉義符，可以通過複寫下面的函數影響其內容
* Window_SynthesisResult.prototype.failureSynthesisText 提示文字內容
* Window_SynthesisResult.prototype.failureRect 提示文字矩形，但只有rect.x和
* rect.y生效，寬度和高度沒有作用
*
* 以上所有视窗的創建都在createAllWindows函數中，他們操作指令的綁定在
* setupHandlers函數中，可在此處進行擴展
* 除了幫助视窗與預覽命令视窗外，所有视窗的構造方法都有（x, y, width, 
* height）四個參數（預覽命令视窗沒有高度height），而物品列表、原料和預覽
* 命令三個视窗有baseScene這第最後一個參數，實例化時傳入this即可
*
* 默認视窗創建順序為：
* 幫助-物品類型-物品列表-預覽命令-結果預覽-原料
*
* 更新日誌
* v1.00
* 插件完成
*
* v1.01
* 修復調用recipeList.simpleData()出錯的問題
*
* v1.02
* 增加合成的自定義限制條件
* 補充部分插件參數的默認值
*
* v1.03
* 刪除拋出LoadRecipeError時的console彈出
*
* v1.04
* 增加合成概率、失敗產物
* 更新至本版本請及時補充插件參數
*/
/*~struct~synthesisItem:
 * @param item
 * @text 物品
 * @type item
 * @default 0
 * @parent Object Selectors
 *
 * @param weapon
 * @text 武器
 * @type weapon
 * @default 0
 * @parent Object Selectors
 *
 * @param armor
 * @text 護甲
 * @type armor
 * @default 0
 * @parent Object Selectors
 */
 /*~struct~recipe:
  * @param recipe1
  * @text 原料1
  * @type struct<synthesisItem>
  * @parent Object Selectors
  *
  * @param recipe2
  * @text 原料2
  * @type struct<synthesisItem>
  * @parent Object Selectors
  *
  * @param produce
  * @text 產物
  * @type struct<synthesisItem>
  * @parent Object Selectors
  */
 /*~struct~synthesisType:
 * @param name
 * @text 類型名
 * @desc 物品類型视窗中顯示的命令文字
 * @parent Object Selectors
 *
 * @param condition
 * @text 物品顯示條件
 * @type note
 * @desc 選擇一個類型後，物品列表顯示內容的條件，在所有物品中篩選，只有這個item對應的condition為true才會顯示出來。
 * @default ""
 * @parent Object Selectors
 */

var Imported = Imported || {};
Imported.CP_Synthesis = true;

var CP = CP || {};
CP.SynthesisManager = CP.SynthesisManager || {};

CP.SynthesisManager.Params = PluginManager.parameters("CP_Synthesis");
CP.SynthesisManager.SYNTHESIS_CONDITION = new Function("condition", "recipe1", "recipe2", "produce"
	, JSON.parse(CP.SynthesisManager.Params["Synthesis Condition"]).trim() + "\nreturn condition;");
CP.SynthesisManager.SYNTHESIS_SUCCESS_RATE = new Function("rate", "recipe1", "recipe2", "produce"
	, JSON.parse(CP.SynthesisManager.Params["Synthesis Success Rate"]).trim() + "\nreturn rate;");

CP.SynthesisManager.UI_SHOW_COMMAND = eval(CP.SynthesisManager.Params["Show In Main Menu"]) || false;
CP.SynthesisManager.UI_MAIN_COMMAND_NAME = CP.SynthesisManager.Params["Main Menu Commamd"].trim();
CP.SynthesisManager.UI_LEFT_WIDTH = CP.SynthesisManager.Params["Left Width"].trim();
CP.SynthesisManager.UI_RESULT_COMMAND_NAME = CP.SynthesisManager.Params["Result Command Name"].trim();
CP.SynthesisManager.UI_SELECT_COMMAND_NAME = CP.SynthesisManager.Params["Select Command Name"].trim();
CP.SynthesisManager.UI_SYNTHESIS_COMMAND_NAME = CP.SynthesisManager.Params["Synthesis Command Name"].trim();
CP.SynthesisManager.UI_CANCEL_COMMAND_NAME = CP.SynthesisManager.Params["Cancel Command Name"].trim();
CP.SynthesisManager.UI_RECIPE_WINDOW_TITLE = CP.SynthesisManager.Params["Recipe Window Title"].trim();
CP.SynthesisManager.UI_NO_RECIPE_TEXT = CP.SynthesisManager.Params["No Recipe Text"].trim();
CP.SynthesisManager.UI_RESULT_WINDOW_TITLE = CP.SynthesisManager.Params["Result Window Title"].trim();
CP.SynthesisManager.UI_SYNTHESIS_RESULT_TEXT = CP.SynthesisManager.Params["Synthesis Result Text"].trim();
CP.SynthesisManager.UI_SYNTHESIS_FAILURE_TEXT = CP.SynthesisManager.Params["Synthesis Failure Text"].trim();
CP.SynthesisManager.UI_SYNTHESIS_NOT_SUCCESS_TEXT = CP.SynthesisManager.Params["Synthesis Not Success Text"].trim();

CP.SynthesisManager._loaded = false;
CP.SynthesisManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.SynthesisManager.DATABASE_LOADED.call(this))
		return false;

	if(!CP.SynthesisManager._loaded){
		try{
			CP.SynthesisManager.loadAllRecipes();
		}catch(err){
			return false;
		}

		CP.SynthesisManager.loadTypeWindowCommands();
		CP.SynthesisManager.loadDefaultProduce();
		CP.SynthesisManager._loaded = true;
	}

	return true;
};

CP.SynthesisManager.loadTypeWindowCommands = function(){
	this.UI_TYPE_COMMANDS = JSON.parse(this.Params["Type Commands"]).map(function(command){
		var c = JSON.parse(command);
		c.condition = JSON.parse(c.condition);
		return c;
	});
};

CP.SynthesisManager.getOneRecipe = function(recipeObject){
	var recipe1 = this.getItemFromRecipeData(recipeObject.recipe1);
	var recipe2 = this.getItemFromRecipeData(recipeObject.recipe2);
	var produce = this.getItemFromRecipeData(recipeObject.produce);

	return new Game_Recipe(recipe1, recipe2, produce);
};

CP.SynthesisManager.getItemFromRecipeData = function(data){
	switch(data[0]){
		case "item":
			return $dataItems[data[1]];
		case "weapon":
			return $dataWeapons[data[1]];
		case "armor":
			return $dataArmors[data[1]];
	}

	return null;
};

CP.SynthesisManager.loadAllRecipes = function(){
	var recipes = this.loadParamRecipes().concat(this.loadExtRecipes());

	this.RECIPES = new Game_RecipeList();
	this.RECIPES.appendRecipes(recipes.map(function(data){
		return this.getOneRecipe(data);
	}, this));
};

CP.SynthesisManager.loadExtRecipes = function(){
	return [];
};

CP.SynthesisManager.loadParamRecipes = function(){
	return JSON.parse(this.Params["Recipe List"]).map(function(str){
		var recipe =  JSON.parse(str);
		var recipe1 = this.getSynthesisItem(recipe.recipe1);
		var recipe2 = this.getSynthesisItem(recipe.recipe2);
		var produce = this.getSynthesisItem(recipe.produce);

		return {
			recipe1: recipe1.getSynthesisItemObject(),
			recipe2: recipe2.getSynthesisItemObject(),
			produce: produce.getSynthesisItemObject()
		};
	}, this);
};

CP.SynthesisManager.loadDefaultProduce = function(){
	this.DEFAULT_PRODUCE = this.getSynthesisItem(this.Params["Default Produce"]);
	this.FAILURE_PRODUCE = this.getSynthesisItem(this.Params["Failure Produce"]);
};

CP.SynthesisManager.getSynthesisItem = function(data){
	data = JSON.parse(data);
	var item = Number(data.item) || 0;
	var weapon = Number(data.weapon) || 0;
	var armor = Number(data.armor) || 0;

	if(item > 0)
		return new Game_SynthesisItem($dataItems[item]);
	if(weapon > 0)
		return new Game_SynthesisItem($dataWeapons[weapon]);
	if(armor > 0)
		return new Game_SynthesisItem($dataArmors[armor]);
	return null;
};

CP.SynthesisManager.findRecipeObject = function(recipe1, recipe2){
	this.RECIPES.startIterate();
	while(this.RECIPES.hasNext()){
		var re = this.RECIPES.next();
		var ros = re.recipeItemObjects();

		if(ros[0].equals(recipe1) && ros[1].equals(recipe2))
			return re;
		if(ros[0].equals(recipe2) && ros[1].equals(recipe1))
			return re;
	}

	return null;
};

CP.SynthesisManager.throwLoadRecipeError = function(message){
	throw new LoadRecipeError(message);
}

//-------------------------------
// Game_SynthesisItem 配方原料與合成物
//-------------------------------
function Game_SynthesisItem(){
	this.initialize.apply(this, arguments);
};

Game_SynthesisItem.prototype = Object.create(Game_Item.prototype);
Game_SynthesisItem.prototype.constructor = Game_SynthesisItem;

Game_SynthesisItem.prototype.initialize = function(item){
	Game_Item.prototype.initialize.call(this, item);
};

Game_SynthesisItem.prototype.setObject = function(item){
	if(DataManager.isItem(item) || DataManager.isWeapon(item) || DataManager.isArmor(item)){
		if(Imported.YEP_ItemCore)
			item = DataManager.getBaseItem(item);
		Game_Item.prototype.setObject.call(this, item);
	}else
		Game_Item.prototype.setObject.call(this, null);
};

Game_SynthesisItem.prototype.object = function(){
	if(this.isSynthesisItem())
		return Game_Item.prototype.object.call(this);

	return null;
};

Game_SynthesisItem.prototype.isSynthesisItem = function(){
	return this.isItem() || this.isWeapon() || this.isArmor();
};

Game_SynthesisItem.prototype.getSynthesisItemObject = function(){
	if(!this.isSynthesisItem())
		return ["", 0];
	return [this._dataClass, this._itemId];
};

Game_SynthesisItem.prototype.equals =function(obj){
	if(!obj instanceof Game_SynthesisItem)
		return false;
	var o1 = this.getSynthesisItemObject();
	var o2 = obj.getSynthesisItemObject();

	return o1[0] === o2[0] && o1[1] === o2[1];
};

//-------------------------------
// Game_Recipe 雙物品合成配方
//-------------------------------
function Game_Recipe(){
	this.initialize.apply(this, arguments);
};

Game_Recipe.prototype.initialize = function(recipeItem1, recipeItem2, produce){
	this._recipeItem1 = new Game_SynthesisItem(null);
	this._recipeItem2 = new Game_SynthesisItem(null);
	this._produceItem = new Game_SynthesisItem(null);

	this.setRecipeData(recipeItem1, recipeItem2, produce);
};

Game_Recipe.prototype.setRecipeData = function(recipeItem1, recipeItem2, produce){
	if(!!recipeItem1)
		this._recipeItem1.setObject(recipeItem1);
	if(!!recipeItem2)
		this._recipeItem2.setObject(recipeItem2);
	if(!!produce)
		this._produceItem.setObject(produce);
};

//是否有效配方
Game_Recipe.prototype.isUsable = function(){
	return this._recipeItem1.isSynthesisItem() && this._recipeItem2.isSynthesisItem() && this._produceItem.isSynthesisItem();
};

//合成原料data
Game_Recipe.prototype.recipeItems = function(){
	var recipes = [];

	if(this.isUsable()){
		recipes.push(this._recipeItem1.object());
		recipes.push(this._recipeItem2.object());
	}

	return recipes;
};

//合成產品data
Game_Recipe.prototype.produceItem = function(){
	// if(this.isUsable())
		return this._produceItem.object();

	return null;
};

Game_Recipe.prototype.recipeObject = function(){
	return {
		recipe1: this._recipeItem1.getSynthesisItemObject(),
		recipe2: this._recipeItem2.getSynthesisItemObject(),
		produce: this._produceItem.getSynthesisItemObject()
	};
};

//下面兩個函數返回Game對象
Game_Recipe.prototype.recipeItemObjects = function(){
	return [this._recipeItem1, this._recipeItem2];
};

Game_Recipe.prototype.produceItemObject = function(){
	return this._produceItem;
};

Game_Recipe.prototype.equals = function(recipe){
	if(!recipe instanceof Game_Recipe)
		return false;

	var r1 = this.recipeItemObjects();
	var r2 = recipe.recipeItemObjects();

	if(r1[0].equals(r2[0]) && r1[1].equals(r2[1]))
		return true;
	if(r1[0].equals(r2[1]) && r1[1].equals(r2[0]))
		return true;
	return false;
};

//-------------------------------
// Game_RecipeList 配方列表對象
//-------------------------------
function Game_RecipeList(){
	this.initialize.apply(this, arguments);
};

Game_RecipeList.prototype.initialize = function(){
	this._data = []; //數據
	this.resetIterate();//迭代器重置
};

Game_RecipeList.prototype.size = function(){
	return !!this._data ? this._data.length : 0;
};

Game_RecipeList.prototype.resetIterate = function(){
	this._index = -1; //當前指針
	this._iterating = false; //迭代器
};

Game_RecipeList.prototype.startIterate = function(){
	this._iterating = true;
	this._index = -1;
};

Game_RecipeList.prototype.hasNext = function(){
	if(!this._iterating)
		return false;
	return !!this._data[this._index + 1];
};

Game_RecipeList.prototype.next = function(){
	if(!this._iterating)
		return null;

	return this._data[++this._index];
};

Game_RecipeList.prototype.contains = function(recipe){
	if(this._data.contains(recipe))
		return true;

	for(var i = 0; i < this._data.length; i++){
		var r = this._data[i];
		if(r.equals(recipe))
			return true;
	}

	return false;
};

Game_RecipeList.prototype.push = function(recipe){
	if(!recipe)
		return false;
	if(!recipe instanceof Game_Recipe)
		return false;
	if(!recipe.isUsable())
		return false;
	if(!this.contains(recipe)){
		this._data.push(recipe);
		this.resetIterate();
		return true;
	}else
		return false;
};

Game_RecipeList.prototype.appendRecipes = function(recipeList){
	var count = 0;
	recipeList.forEach(function(recipe){
		if(this.push(recipe))
			count++;
	}, this);

	return count;
};

Game_RecipeList.prototype.simpleData = function(){
	var data = new Array();

	this.startIterate();
	while(this.hasNext()){
		var re = this.next();
		data.push(re.recipeObject());
	}

	return data;
};

//-------------------------------
// Game_Party
//-------------------------------
Game_Party.prototype.execRecipe = function(recipeItem1, recipeItem2, produce){
	if(!recipeItem1 || !recipeItem2 || !produce)
		return false;

	if(this.hasItem(recipeItem1) && this.hasItem(recipeItem2)){
		this.loseItem(recipeItem1, 1);
		this.loseItem(recipeItem2, 1);
		this.gainItem(produce, 1);
		return true;
	}

	return false;
};

//-------------------------------
// Scene_Synthesis 合成界面
//-------------------------------
function Scene_Synthesis(){
	this.initialize.apply(this, arguments);
};

Scene_Synthesis.prototype = Object.create(Scene_MenuBase.prototype);
Scene_Synthesis.prototype.constructor = Scene_Synthesis;

Scene_Synthesis.prototype.initialize = function(){
	Scene_MenuBase.prototype.initialize.call(this);

	this.setLeftRecipeItem(null);
	this.setRightRecipeItem(null);
};

Scene_Synthesis.prototype.setLeftRecipeItem = function(item){
	this._recipeItemLeft = item;
};

Scene_Synthesis.prototype.leftRecipeItem = function(){
	return this._recipeItemLeft;
};

Scene_Synthesis.prototype.setRightRecipeItem = function(item){
	this._recipeItemRight = item;
};

Scene_Synthesis.prototype.rightRecipeItem = function(){
	return this._recipeItemRight;
};

Scene_Synthesis.prototype.findRecipe = function(){
	var leftItem = new Game_SynthesisItem(this._recipeItemLeft);
	var rightItem = new Game_SynthesisItem(this._recipeItemRight);

	return CP.SynthesisManager.findRecipeObject(leftItem, rightItem);
};

Scene_Synthesis.prototype.create = function(){
    Scene_MenuBase.prototype.create.call(this);

    this.createAllWindows();
    this.setupHandlers();
};

Scene_Synthesis.prototype.createAllWindows = function(){
	this.createHelpWindow();
    this.createTypeSelectWindow();
    this.createListWindow();
    this.createCommandWindow();
    this.createResultWindow();
    this.createRecipeWindow();
};

Scene_Synthesis.prototype.setupHandlers = function(){
	this._typeWindow.setOnSelectMethod(this.onTypeSelect.bind(this));
	this._typeWindow.setHandler("ok", this.onTypeOk.bind(this));
	this._typeWindow.setHandler("cancel", this.onTypeCancel.bind(this));

	this._listWindow.setHandler("ok", this.onListOk.bind(this));
	this._listWindow.setHandler("cancel", this.onListCancel.bind(this));

	this._recipeWindow.setHandler("ok", this.onRecipeOk.bind(this));
	this._recipeWindow.setHandler("cancel", this.popScene.bind(this));

	this._resultWindow.setHandler("synthesis", this.onResultOk.bind(this));
	this._resultWindow.setHandler("cancel", this.onResultCancel.bind(this));

	this._commandWindow.setHandler("select", this.onCommandSelect.bind(this));
	this._commandWindow.setHandler("result", this.onCommandResult.bind(this));
	this._commandWindow.setHandler("cancel", this.onCommandCancel.bind(this));
};

Scene_Synthesis.prototype.createTypeSelectWindow = function(){
	var y = this._helpWindow.height;
	this._typeWindow = new Window_TypeSelect(0, y);

	this.addWindow(this._typeWindow);
};

Scene_Synthesis.prototype.onTypeSelect = function(){
	this._listWindow.setItemType(this._typeWindow.index());
	this._listWindow.refresh();
};

Scene_Synthesis.prototype.onTypeOk = function(){
	this._typeWindow.deactivate();
	this._listWindow.activate();
	this._listWindow.select(0);
};

Scene_Synthesis.prototype.onTypeCancel = function(){
	this._typeWindow.deselect();
	this._typeWindow.deactivate();
	this._recipeWindow.activate();
};

Scene_Synthesis.prototype.createListWindow = function(){
	var y = this._typeWindow.y + this._typeWindow.height;
	var width = eval(CP.SynthesisManager.UI_LEFT_WIDTH);
	var height = Graphics.boxHeight - y;

	this._listWindow = new Window_SynthesisItemList(0, y, width, height, this);
	this._listWindow.setHelpWindow(this._helpWindow);

	this.addWindow(this._listWindow);
};

Scene_Synthesis.prototype.onListOk = function(){
	this.setCurrentItem(this._listWindow.item());

	this._listWindow.deselect();
	this._listWindow.refresh();
	this._listWindow.deactivate();

	this._typeWindow.deselect();

	this._recipeWindow.refresh();
	this._recipeWindow.activate();

	this._commandWindow.refresh();
};

Scene_Synthesis.prototype.setCurrentItem = function(item){
	if(this._recipeWindow.index() % 2 === 0)
		this.setLeftRecipeItem(item);
	else
		this.setRightRecipeItem(item);
};

Scene_Synthesis.prototype.onListCancel = function(){
	this._listWindow.deselect();
	this._listWindow.deactivate();
	this._typeWindow.activate();
};

Scene_Synthesis.prototype.createCommandWindow = function(){
	var x = this._listWindow.x + this._listWindow.width;
	var y = Graphics.boxHeight - this._listWindow.fittingHeight(1);
	var width = Graphics.boxWidth - x;

	this._commandWindow = new Window_SynthesisCommand(x, y, width, this);
	this.addWindow(this._commandWindow);
};

Scene_Synthesis.prototype.onCommandSelect = function(){
	this._commandWindow.deactivate();
	this._commandWindow.deselect();
	this._typeWindow.activate();
	this._typeWindow.select(0);
};

Scene_Synthesis.prototype.onCommandResult = function(){
	var recipe = this.findRecipe();
	var produce = !!CP.SynthesisManager.DEFAULT_PRODUCE ? CP.SynthesisManager.DEFAULT_PRODUCE.object() : null;
	if(!!recipe)
		produce = recipe.produceItem();

	this._commandWindow.deactivate();

	this._resultWindow.setRecipeItems(this.leftRecipeItem(), this.rightRecipeItem());
	this._resultWindow.setSynthesisResult(produce);
	this._resultWindow.refresh();
	this._resultWindow.activate();
	this._resultWindow.select(0);
	this._resultWindow.callUpdateHelp();
};

Scene_Synthesis.prototype.onCommandCancel = function(){
	this._commandWindow.deselect();
	this._commandWindow.deactivate();

	this._recipeWindow.activate();
};

Scene_Synthesis.prototype.createResultWindow = function(){
	var x = this._listWindow.x + this._listWindow.width;
	var y = this._helpWindow.y + this._helpWindow.height;
	var width = Graphics.boxWidth - x;
	var height = Math.round((Graphics.boxHeight - y - 10) / 2);

	this._resultWindow = new Window_SynthesisResult(x, y, width, height);
	this._resultWindow.setHelpWindow(this._helpWindow);
	this.addWindow(this._resultWindow);
};

Scene_Synthesis.prototype.onResultOk = function(){
	var recipe1 = this._resultWindow.recipeItem(1);
	var recipe2 = this._resultWindow.recipeItem(2);
	var produce = this._resultWindow.synthesisResult();
	var failureProduce = null;
	var rate = CP.SynthesisManager.SYNTHESIS_SUCCESS_RATE.call(this, 0, recipe1, recipe2, produce);
	var successful = Math.random() < rate;
	if(!successful)
		failureProduce = this.failureResult(recipe1, recipe2, produce);

	$gameParty.execRecipe(recipe1, recipe2, successful ? produce : failureProduce);
	this.showResultInfo(produce, failureProduce);

	this.setLeftRecipeItem(null);
	this.setRightRecipeItem(null);

	this._resultWindow.initData();
	this._resultWindow.refresh();
	this._recipeWindow.refresh();
	this._recipeWindow.activate();

	this._resultWindow.deselect();
	this._resultWindow.deactivate();
	this._commandWindow.deselect();
	this._commandWindow.deactivate();
	this._commandWindow.refresh();
	this._listWindow.refresh();

	return [successful, successful ? produce : failureProduce];
};

Scene_Synthesis.prototype.failureResult = function(recipe1, recipe2, produce){
	return CP.SynthesisManager.FAILURE_PRODUCE.object();
};

Scene_Synthesis.prototype.showResultInfo = function(produce, failureProduce){
	if(!failureProduce)
		this._helpWindow.setText(CP.SynthesisManager.UI_SYNTHESIS_RESULT_TEXT.format(produce.name));
	else
		this._helpWindow.setText(CP.SynthesisManager.UI_SYNTHESIS_NOT_SUCCESS_TEXT.format(produce.name
			, failureProduce.name));
};

Scene_Synthesis.prototype.onResultCancel = function(){
	this._resultWindow.deselect();
	this._resultWindow.deactivate();
	this._commandWindow.activate();
};

Scene_Synthesis.prototype.createRecipeWindow = function(){
	var x = this._resultWindow.x;
	var y = this._resultWindow.y + this._resultWindow.height;
	var width = Graphics.boxWidth - x;
	var height = this._commandWindow.y - y;

	this._recipeWindow = new Window_RecipeItem(x, y, width, height, this);
	this.addWindow(this._recipeWindow);
};

Scene_Synthesis.prototype.onRecipeOk = function(){
	this._recipeWindow.deactivate();

	var item = this._recipeWindow.currentItem();
	if(!item){
		this._typeWindow.activate();
		this._typeWindow.select(0);
	}else{
		this._commandWindow.activate();
		this._commandWindow.select(0);
	}
};

//-------------------------------
// Window_TypeSelect
//-------------------------------
function Window_TypeSelect(){
	this.initialize.apply(this, arguments);
};

Window_TypeSelect.prototype = Object.create(Window_Selectable.prototype);
Window_TypeSelect.prototype.constructor = Window_TypeSelect;

Window_TypeSelect.prototype.initialize = function(x, y){
	var width = eval(CP.SynthesisManager.UI_LEFT_WIDTH);
	var height = this.fittingHeight(1);

	Window_Selectable.prototype.initialize.	call(this, x, y, width, height);

	this.refresh();
};

Window_TypeSelect.prototype.maxCols = function(){
	return this.maxItems();
};

Window_TypeSelect.prototype.maxItems = function(){
	return CP.SynthesisManager.UI_TYPE_COMMANDS.length;
};

Window_TypeSelect.prototype.setOnSelectMethod = function(method){
	this._onSelectMethod = method;
};

Window_TypeSelect.prototype.select = function(index){
	Window_Selectable.prototype.select.call(this, index);

	if(!!this._onSelectMethod)
		this._onSelectMethod.call(this);
};

Window_TypeSelect.prototype.drawItem = function(index){
	var rect = this.itemRect(index);
	var command = CP.SynthesisManager.UI_TYPE_COMMANDS[index];

	this.drawText(command.name, rect.x, rect.y, rect.width, "center");
};

//-------------------------------
// Window_SynthesisItemList
//-------------------------------
function Window_SynthesisItemList(){
	this.initialize.apply(this,arguments);
};

Window_SynthesisItemList.prototype = Object.create(Window_ItemList.prototype);
Window_SynthesisItemList.prototype.constructor = Window_SynthesisItemList;

Window_SynthesisItemList.prototype.initialize = function(x, y, width, height, baseScene){
	Window_ItemList.prototype.initialize.call(this, x, y, width, height);

	this._baseScene = baseScene;

	this.setItemType(-1);
};

Window_SynthesisItemList.prototype.setItemType = function(typeId){
	this._itemTypeId = typeId;
};

Window_SynthesisItemList.prototype.maxCols = function(){
	return 1;
};

Window_SynthesisItemList.prototype.isEnabled = function(item){
	return true;
};

Window_SynthesisItemList.prototype.includes = function(item){
	if(this._itemTypeId < 0 || this._itemTypeId >= CP.SynthesisManager.UI_TYPE_COMMANDS.length)
		return false;

	var condition = false;
	try{
		eval(CP.SynthesisManager.UI_TYPE_COMMANDS[this._itemTypeId].condition);
	}catch(err){
		console.error(err);
		condition = false;
	}

	return condition && this.itemNum(item) > 0;
};

Window_SynthesisItemList.prototype.itemNum = function(item){
	var num = $gameParty.numItems(item);
	if(this._baseScene.leftRecipeItem() === item)
		num--;
	if(this._baseScene.rightRecipeItem() === item)
		num--;

	return num;
};

Window_SynthesisItemList.prototype.drawItemNumber = function(item, x, y, width){
	this.drawText("\u00d7", x, y, width - this.textWidth('00'), 'right');
	this.drawText(this.itemNum(item), x, y, width, 'right');
};

//-------------------------------
// Window_RecipeItem
//-------------------------------
function Window_RecipeItem(){
	this.initialize.apply(this, arguments);
};

Window_RecipeItem.prototype = Object.create(Window_Selectable.prototype);
Window_RecipeItem.prototype.constructor = Window_RecipeItem;

Window_RecipeItem.prototype.initialize = function(x, y ,width, height, baseScene){
	Window_Selectable.prototype.initialize.call(this, x, y, width, height);

	this._baseScene = baseScene;

	this.refresh();
	this.activate();
	this.select(0);
};

Window_RecipeItem.prototype.leftRecipeItem = function(){
	return !!this._baseScene ? this._baseScene.leftRecipeItem() : null;
};

Window_RecipeItem.prototype.rightRecipeItem = function(){
	return !!this._baseScene ? this._baseScene.rightRecipeItem() : null;
};

Window_RecipeItem.prototype.maxItems = function(){
	return 2;
};

Window_RecipeItem.prototype.maxCols = function(){
	return 2;
};

Window_RecipeItem.prototype.currentItem = function(){
	if(this.index() % 2 === 0)
		return this.leftRecipeItem();
	else
		return this.rightRecipeItem();
};

Window_RecipeItem.prototype.itemRect = function(index){
	var rect = Window_Selectable.prototype.itemRect.call(this, index + this.maxCols());

	rect.x += this.standardPadding();
	rect.width -= this.standardPadding() * 2;

	rect.height = this.contents.height - rect.y;

	return rect;
};

Window_RecipeItem.prototype.drawAllItems = function(){
	Window_Selectable.prototype.drawAllItems.call(this);

	this.drawRecipeTitle(CP.SynthesisManager.UI_RECIPE_WINDOW_TITLE);
};

Window_RecipeItem.prototype.titleRect = function(){
	var rect = Window_Selectable.prototype.itemRect.call(this, 0);

	rect.width *= 2;

	return rect;
};

Window_RecipeItem.prototype.drawRecipeTitle = function(title){
	var rect = this.titleRect();
	var offsetX = Math.round((rect.width - this.textWidth(title)) / 2);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(title, rect.x + offsetX, rect.y, this.textWidth(title));
};

Window_RecipeItem.prototype.drawItem = function(index){
	var rect = this.itemRect(index);

	if(index % 2 === 0)
		this.drawRecipeItem(rect, this.leftRecipeItem());
	else
		this.drawRecipeItem(rect, this.rightRecipeItem());
};

Window_RecipeItem.prototype.drawRecipeItem = function(rect, item){
	if(!item){
		this.drawDarkRect(rect);
		this.drawNoRecipeText(rect);
	}else{
		this.drawItemLargePicture(rect, item);
		this.drawItemName(rect, item);
	}
};

Window_RecipeItem.prototype.itemHasPictureImage = function(item){
	if(!Imported.YEP_X_ItemPictureImg)
		return false;
	if(!item)
		return false;
		
	var filename = ItemManager.getItemPictureImageFilename(item);
	return filename !== '';
};

Window_RecipeItem.prototype.drawItemLargePicture = function(rect, item){
	if(this.itemHasPictureImage(item))
		this.drawItemPicture(rect, item);
	else
		this.drawItemLargeIcon(rect, item);
};

Window_RecipeItem.prototype.drawItemPicture = function(rect, item){
	var bitmap = ItemManager.getItemPictureImage(item);
	bitmap.addLoadListener((bitmap) => {
		var pw = bitmap.width;
	    var ph = bitmap.height;
	    var sx = 0;
	    var sy = 0;
	    var dw = pw;
	    var dh = ph;
	    if(dw > rect.width / 2){
	    	var rate = rect.width / 2 / dw;
	       dw = Math.floor(dw * rate);
	       dh = Math.floor(dh * rate);
	   }
	   if(dh > rect.height / 2){
		  	var rate = rect.height / 2 / dh;
		    dw = Math.floor(dw * rate);
		    dh = Math.floor(dh * rate);
		}

		var dx = Math.round(rect.x + rect.width / 4);
		var dy = Math.round(rect.y + rect.height / 4);
		this.contents.blt(bitmap, sx, sy, pw, ph, dx, dy, dw, dh);
	});
};

Window_RecipeItem.prototype.drawItemLargeIcon = function(rect, item){
	var iconIndex = item.iconIndex;
    var bitmap = ImageManager.loadSystem('IconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    var dw = Math.round(rect.width / 2);
    var dh = Math.round(rect.height / 2);
    dw = Math.min(dw, dh);
    dh = dw;
    var dx = rect.x + dw / 2;
    var dy = rect.y + dh / 2;
    this.contents._context.imageSmoothingEnabled = false;
    this.contents.blt(bitmap, sx, sy, pw, ph, dx, dy, dw, dh);
    this.contents._context.imageSmoothingEnabled = true;
};

Window_RecipeItem.prototype.drawItemName = function(rect, item){
	var x = Math.round(rect.x + rect.width / 4);
	var y = Math.round(rect.y + 3 * rect.height / 4);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(item.name, x, y, 3 * rect.width / 4, "center");
};

Window_RecipeItem.prototype.drawNoRecipeText = function(rect){
	var width = this.textWidth(CP.SynthesisManager.UI_NO_RECIPE_TEXT);
	var offsetX = Math.round((rect.width - width) / 2);
	var offsetY = Math.round(rect.height / 2);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(CP.SynthesisManager.UI_NO_RECIPE_TEXT, rect.x + offsetX, rect.y + offsetY, width, rect.height, "center");
};

Window_RecipeItem.prototype.drawDarkRect = function(rect){
	var color = this.gaugeBackColor();
    this.changePaintOpacity(false);
    this.contents.fillRect(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, color);
    this.changePaintOpacity(true);
};

//-------------------------------
// Window_SynthesisResult
//-------------------------------
function Window_SynthesisResult(){
	this.initialize.apply(this, arguments);
};

Window_SynthesisResult.prototype = Object.create(Window_Command.prototype);
Window_SynthesisResult.prototype.constructor = Window_SynthesisResult;

Window_SynthesisResult.prototype.initialize = function(x, y, width, height){
	Window_Command.prototype.initialize.call(this, x, y);

	this.initData();

	this.setWidthAndHeight(width, height);
	this.refresh();

	this.deselect();
	this.deactivate();
};

Window_SynthesisResult.prototype.setWidthAndHeight = function(width, height){
	this.width = width;
	this.height = height;
};

Window_SynthesisResult.prototype.makeCommandList = function(){
	this.addCommand(CP.SynthesisManager.UI_SYNTHESIS_COMMAND_NAME, "synthesis", this.canExecSynthesis());
	this.addCommand(CP.SynthesisManager.UI_CANCEL_COMMAND_NAME, "cancel");
};

Window_SynthesisResult.prototype.canExecSynthesis = function(){
	return this.hasSynthesisResult() && this.meetsSynthesisCondition(this._recipeItem1, this._recipeItem2, this._synthesisResult);
};

Window_SynthesisResult.prototype.hasSynthesisResult = function(){
	return !!this._recipeItem1 && !!this._recipeItem2 && !!this._synthesisResult;
};

Window_SynthesisResult.prototype.meetsSynthesisCondition = function(recipe1, recipe2, produce){
	try{
		return CP.SynthesisManager.SYNTHESIS_CONDITION.call(this, false, recipe1, recipe2, produce);
	}catch(err){
		console.error(err);
		return false;
	}
};

Window_SynthesisResult.prototype.initData = function(){
	this.setRecipeItems(null, null);
	this.setSynthesisResult(null);
};

Window_SynthesisResult.prototype.setRecipeItems = function(item1, item2){
	this._recipeItem1 = item1;
	this._recipeItem2 = item2;
};

Window_SynthesisResult.prototype.setSynthesisResult = function(result){
	this._synthesisResult = result;
};

//index從1到2
Window_SynthesisResult.prototype.recipeItem = function(index){
	if(index === 1)
		return this._recipeItem1;
	if(index === 2)
		return this._recipeItem2;
	return null;
};

Window_SynthesisResult.prototype.synthesisResult = function(){
	return this._synthesisResult;
};

Window_SynthesisResult.prototype.updateHelp = function(){
	this.setHelpWindowItem(this._synthesisResult);
};

Window_SynthesisResult.prototype.itemRect = function(index){
	var rect = Window_Selectable.prototype.itemRect.call(this, index + 1);

	rect.x += Math.round(2 * this.contents.width / 3);
	rect.y += this.standardPadding() * index;
	rect.width -= rect.x;
	
	return rect;
};

Window_SynthesisResult.prototype.titleRect = function(){
	var rect = Window_Selectable.prototype.itemRect.call(this, 0);

	rect.width *= 2;

	return rect;
};

Window_SynthesisResult.prototype.resultRect = function(){
	var rect = Window_Selectable.prototype.itemRect.call(this, 1);

	var width = Math.round(2 * rect.width / 3);
	var height = this.contents.height - this. fittingHeight(1);

	rect.width = Math.min(width, height);
	rect.height = rect.width;

	return rect;
};

Window_SynthesisResult.prototype.failureRect = function(){
	var rect = this.resultRect();
	rect.x = rect.x + rect.width;
	rect.y += (this.lineHeight() * 2 + this.standardPadding());
	return rect;
};

Window_SynthesisResult.prototype.drawDarkRect = function(rect){
	var color = this.gaugeBackColor();
    this.changePaintOpacity(false);
    this.contents.fillRect(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, color);
    this.changePaintOpacity(true);
};

Window_SynthesisResult.prototype.drawNoRecipeText = function(rect){
	var width = this.textWidth(CP.SynthesisManager.UI_NO_RECIPE_TEXT);
	var offsetX = Math.round((rect.width - width) / 2);
	var offsetY = Math.round(rect.height / 2);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(CP.SynthesisManager.UI_NO_RECIPE_TEXT, rect.x + offsetX, rect.y + offsetY, width);
};

Window_SynthesisResult.prototype.itemHasPictureImage = function(item){
	if(!Imported.YEP_X_ItemPictureImg)
		return false;
	if(!item)
		return false;
		
	var filename = ItemManager.getItemPictureImageFilename(item);
	return filename !== '';
};

Window_SynthesisResult.prototype.drawItemLargePicture = function(rect, item){
	if(this.itemHasPictureImage(item))
		this.drawItemPicture(rect, item);
	else
		this.drawItemLargeIcon(rect, item);
};

Window_SynthesisResult.prototype.drawItemPicture = function(rect, item){
	var bitmap = ItemManager.getItemPictureImage(item);
	bitmap.addLoadListener((bitmap) => {
		var pw = bitmap.width;
	    var ph = bitmap.height;
	    var sx = 0;
	    var sy = 0;
	    var dw = pw;
	    var dh = ph;
	    if(dw > rect.width / 2){
	    	var rate = rect.width / 2 / dw;
	       dw = Math.floor(dw * rate);
	       dh = Math.floor(dh * rate);
	   }
	   if(dh > rect.height / 2){
		  	var rate = rect.height / 2 / dh;
		    dw = Math.floor(dw * rate);
		    dh = Math.floor(dh * rate);
		}

		var dx = Math.round(rect.x + rect.width / 4);
		var dy = Math.round(rect.y + rect.height / 4);
		this.contents.blt(bitmap, sx, sy, pw, ph, dx, dy, dw, dh);
	});
};

Window_SynthesisResult.prototype.drawItemLargeIcon = function(rect, item){
	var iconIndex = item.iconIndex;
    var bitmap = ImageManager.loadSystem('IconSet');
    var pw = Window_Base._iconWidth;
    var ph = Window_Base._iconHeight;
    var sx = iconIndex % 16 * pw;
    var sy = Math.floor(iconIndex / 16) * ph;
    var dw = Math.round(rect.width / 2);
    var dh = Math.round(rect.height / 2);
    dw = Math.min(dw, dh);
    dh = dw;
    var dx = rect.x + dw / 2;
    var dy = rect.y + dh / 2;
    this.contents._context.imageSmoothingEnabled = false;
    this.contents.blt(bitmap, sx, sy, pw, ph, dx, dy, dw, dh);
    this.contents._context.imageSmoothingEnabled = true;
};

Window_SynthesisResult.prototype.drawItemName = function(rect, item){
	var x = Math.round(rect.x + rect.width / 4);
	var y = Math.round(rect.y + 3 * rect.height / 4);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(item.name, x, y, 3 * rect.width / 4, "center");
};

Window_SynthesisResult.prototype.drawAllItems = function(){
	Window_Selectable.prototype.drawAllItems.call(this);

	this.drawResult();
};

Window_SynthesisResult.prototype.drawResult = function(){
	this.drawTitle();
	this.drawResultItem(this.resultRect());
	this.drawFailureSynthesis(this.failureRect(), this._recipeItem1, this._recipeItem2, this._synthesisResult);
};

Window_SynthesisResult.prototype.drawTitle = function(){
	var rect = this.titleRect();
	var x = Math.round(rect.x + rect.width / 8);
	var width = Math.round(7 * rect.width / 8);

	this.resetFontSettings();
	this.resetTextColor();

	this.drawText(CP.SynthesisManager.UI_RESULT_WINDOW_TITLE, x, rect.y, width);
};

Window_SynthesisResult.prototype.drawResultItem = function(rect){
	if(!this.hasSynthesisResult()){
		this.drawDarkRect(rect);
		this.drawNoRecipeText(rect);
	}else{
		this.drawItemLargePicture(rect, this._synthesisResult);
		this.drawItemName(rect, this._synthesisResult);
	}
};

Window_SynthesisResult.prototype.drawFailureSynthesis = function(rect, recipe1, recipe2, produce){
	if(!!recipe1 && recipe2 && produce && !this.meetsSynthesisCondition(recipe1, recipe2, produce))
		this.drawTextEx(this.failureSynthesisText(recipe1, recipe2, produce), rect.x, rect.y);
};

Window_SynthesisResult.prototype.failureSynthesisText = function(recipe1, recipe2, produce){
	return CP.SynthesisManager.UI_SYNTHESIS_FAILURE_TEXT.format(recipe1.name, recipe2.name, produce.name);
};

//解析換行標記<br>
Window_SynthesisResult.prototype.convertEscapeCharacters = function(text){
	text = text.replace(/<br>/g, "\n");
	return Window_Command.prototype.convertEscapeCharacters.call(this, text);
};

//-------------------------------
// Window_SynthesisCommand
//-------------------------------
function Window_SynthesisCommand(){
	this.initialize.apply(this, arguments);
};

Window_SynthesisCommand.prototype = Object.create(Window_HorzCommand.prototype);
Window_SynthesisCommand.prototype.constructor = Window_SynthesisCommand;

Window_SynthesisCommand.prototype.initialize = function(x, y, width, baseScene){
	Window_HorzCommand.prototype.initialize.call(this, x, y);

	this._baseScene = baseScene;

	this.setWidthAndHeight(width, this.fittingHeight(1));
	this.deselect();
	this.deactivate();

	this.refresh();
};

Window_SynthesisCommand.prototype.setWidthAndHeight = function(width, height){
	this.width = width;
	this.height = height;
};

Window_SynthesisCommand.prototype.makeCommandList = function(){
	this.addCommand(CP.SynthesisManager.UI_SELECT_COMMAND_NAME, "select");
	this.addCommand(CP.SynthesisManager.UI_RESULT_COMMAND_NAME, "result", this.canShowResult());
};

Window_SynthesisCommand.prototype.canShowResult = function(){
	return !!this._baseScene && !!this._baseScene.leftRecipeItem() && !!this._baseScene.rightRecipeItem();
};

//-------------------------------
// Window_MenuCommand
//-------------------------------
CP.SynthesisManager.ADD_ORGINAL_COMMANDS = Window_MenuCommand.prototype.addOriginalCommands;
Window_MenuCommand.prototype.addOriginalCommands = function(){
	CP.SynthesisManager.ADD_ORGINAL_COMMANDS.call(this);

	if(CP.SynthesisManager.UI_SHOW_COMMAND)
		this.addSynthesisCommand();
};

Window_MenuCommand.prototype.addSynthesisCommand = function(){
	this.addCommand(CP.SynthesisManager.UI_MAIN_COMMAND_NAME, "synthesis");
};

//-------------------------------
// Scene_Menu
//-------------------------------
CP.SynthesisManager.CREATE_MAIN_COMMAND_WINDOW = Scene_Menu.prototype.createCommandWindow;
Scene_Menu.prototype.createCommandWindow = function() {
	CP.SynthesisManager.CREATE_MAIN_COMMAND_WINDOW.call(this);

	if(CP.SynthesisManager.UI_SHOW_COMMAND)
		this._commandWindow.setHandler("synthesis", this.commandSynthesis.bind(this));
};

Scene_Menu.prototype.commandSynthesis = function(){
	SceneManager.push(Scene_Synthesis);
};

//-------------------------------
// LoadRecipeError 讀取文件阻塞拋出的異常類
// 異常類規則【message/name/stack】
// stack需要
//-------------------------------
function LoadRecipeError(){
	this.initialize.apply(this, arguments);
};

LoadRecipeError.prototype = Object.create(Error.prototype);
LoadRecipeError.prototype.constructor = LoadRecipeError;

LoadRecipeError.prototype.initialize = function(message){
	this.message = message || "LoadRecipeError";
	this.name = "LoadRecipeError";
	this.stack = new Error().stack;
};